using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Snake.Client
{
    public class SnakeGame : Microsoft.Xna.Framework.Game
    {
        private readonly List<Player> _playersList = new List<Player>();
        private Food _food;

        public SnakeGame()
        {
            Screen.CreateGraphicsDevice(new GraphicsDeviceManager(this));
            Content.RootDirectory = "Content";
        }

        private bool _allDead
        {
            get
            {
                foreach (var player in _playersList)
                {
                    if (!player.Dead)
                    {
                        return false;
                    }
                }
                return true;
            }
        }

        protected override void Initialize()
        {
            Screen.Initialize(GameInfo.RequestedScreenWidth, GameInfo.RequestedScreenHeight);
            _food = new Food();

            _SetDefaultKeyBinds();

            base.Initialize();
        }
        protected override void LoadContent()
        {
            Screen.LoadResourses
            (
                Content.Load<Texture2D>("segment"),
                Content.Load<Texture2D>("background"),
                Content.Load<Texture2D>("food"),
                Content.Load<SpriteFont>("SnakeFont")
            );
            Sound.LoadResourses
            (
                Content.Load<SoundEffect>("food_collected_sound")
            );
        }
        protected override void UnloadContent()
        {
        }
        protected override void Update(GameTime gameTime)
        {
            _ProcessKeyboard();

            foreach (var player in _playersList)
            {
                if (!player.Dead)
                {
                    player.Body.Move();
                    player.ProcessFoodCollecting(_food);
                    player.ProcessCollisions(_playersList);
                }
            }
            if (_allDead && Keyboard.GetState().IsKeyDown(Keys.Enter))
            {
                Exit();
            }

            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            Screen.BeginDrawing();
            Screen.DrawBackground();
            Screen.DrawFood(_food.Position);
            for (int playerIndex = 0; playerIndex < _playersList.Count; playerIndex++)
            {
                var player = _playersList[playerIndex];
                Screen.DrawSnake(player.Body, player.Health);
                Screen.DrawPlayerStatus(player, playerIndex);
            }
            if (_allDead)
            {
                Screen.DrawDeathScreen();
            }
            Screen.EndDrawing();

            base.Draw(gameTime);
        }

        private void _ProcessKeyboard()
        {
            var pressedKey = Keyboard.GetState().GetPressedKeys();

            foreach (var player in _playersList)
            {
                SnakeEvent snakeEvent = player.Controls.ParseKey(pressedKey);

                switch (snakeEvent)
                {
                    case SnakeEvent.NoAction:
                        continue;

                    case SnakeEvent.Scatter:
                        player.Body.Scatter();
                        break;

                    case SnakeEvent.Quit:
                        player.Dead = true;
                        break;

                    default:
                        player.Body.HeadDirectionByEvent(snakeEvent);
                        break;
                }
            }
        }
        private void _SetDefaultKeyBinds()
        {
            if (GameInfo.NumberOfPlayers > 0)
            {
                var controls = new Controls();
                controls.Bind(Keys.Up, SnakeEvent.Up);
                controls.Bind(Keys.Down, SnakeEvent.Down);
                controls.Bind(Keys.Right, SnakeEvent.Right);
                controls.Bind(Keys.Left, SnakeEvent.Left);
                controls.Bind(Keys.Space, SnakeEvent.Scatter);
                controls.Bind(Keys.Escape, SnakeEvent.Quit);
                _playersList.Add(new Player(new Body(), controls, "First Player"));
            }

            if (GameInfo.NumberOfPlayers > 1)
            {
                var controls = new Controls();
                controls.Bind(Keys.W, SnakeEvent.Up);
                controls.Bind(Keys.S, SnakeEvent.Down);
                controls.Bind(Keys.D, SnakeEvent.Right);
                controls.Bind(Keys.A, SnakeEvent.Left);
                controls.Bind(Keys.X, SnakeEvent.Scatter);
                controls.Bind(Keys.Q, SnakeEvent.Quit);
                _playersList.Add(new Player(new Body(), controls, "Second Player"));
            }
            if (GameInfo.NumberOfPlayers > 2)
            {
                var controls = new Controls();
                controls.Bind(Keys.NumPad8, SnakeEvent.Up);
                controls.Bind(Keys.NumPad5, SnakeEvent.Down);
                controls.Bind(Keys.NumPad6, SnakeEvent.Right);
                controls.Bind(Keys.NumPad4, SnakeEvent.Left);
                controls.Bind(Keys.NumPad2, SnakeEvent.Scatter);
                controls.Bind(Keys.Q, SnakeEvent.Quit);
                _playersList.Add(new Player(new Body(), controls, "Third Player"));
            }
            if (GameInfo.NumberOfPlayers > 3)
            {
                var controls = new Controls();
                controls.Bind(Keys.Z, SnakeEvent.Up);
                controls.Bind(Keys.H, SnakeEvent.Down);
                controls.Bind(Keys.J, SnakeEvent.Right);
                controls.Bind(Keys.G, SnakeEvent.Left);
                controls.Bind(Keys.N, SnakeEvent.Scatter);
                controls.Bind(Keys.Q, SnakeEvent.Quit);
                _playersList.Add(new Player(new Body(), controls, "Fourth Player"));
                GameInfo.NumberOfPlayers = 4;
            }
        }
    }
}